package binder.model;

import java.beans.Beans;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * All bind bean factory, it will ensure those bind bean object shared.
 * <p>
 */
public class BindBeans
{
	private static Map<Class<?>, Object> beanMap = new ConcurrentHashMap<Class<?>, Object>();

	private static Lock lock = new ReentrantLock();

	/**
	 * get shared bean object by bean class
	 * 
	 * @param beanClass
	 * @return Object
	 */
	@SuppressWarnings("unchecked")
	public static <T> T lookup(Class<T> beanClass)
	{
		lock.lock();
		try
		{
			T beanObject = (T) beanMap.get(beanClass);
			if (beanObject == null)
			{
				beanObject = createBeanObject(beanClass);
				beanMap.put(
					beanClass, beanObject);
			}
			return beanObject;
		}
		finally
		{
			lock.unlock();
		}
	}

	/**
	 * instantiate bean use its default constructor
	 * 
	 * @param beanClass
	 * @return Object
	 */
	@SuppressWarnings("unchecked")
	private static <T> T createBeanObject(Class<T> beanClass)
	{
		try
		{
			return (T) Beans.instantiate(
				beanClass.getClassLoader(), beanClass.getName());
		}
		catch (Exception e)
		{
			e.printStackTrace();
			throw new IllegalArgumentException(e);
		}
	}

	public static void clean()
	{
		lock.lock();
		try
		{
			beanMap.clear();
		}
		finally
		{
			lock.unlock();
		}
	}
}
